/**
 ********************************************************************
 * @author roocket
 * @file    dispenser.c
 * @version V0.0.0
 * @date    2024/3/22
 * @brief   This file is to indicate dispensering data functions. 
 * @attention Code file rules:
 * rule: file encoding use UTF8;
 * rule: max line length 120 characters;
 * rule: line separator \r\n;
 * rule: use clion auto code format tool.
 */
#include "dispenser.h"

int dispenser_shmt_init(struct dispenser_config *dip_cfg)
{
    if(0 != pthread_mutex_init(&dip_cfg->rw_lock, NULL)) {
        perror("Mutex init failed\n");
        return -1;
    }

    int id;
    key_t key;
    key = ftok(DISPENSER_SHMT_LOCATION, 0x6666);
    id = shmget(key, DISPENSER_SHMT_MALLOC_BUFFER, IPC_CREAT |0666);
    if (-1 == id) {
        perror("shmget");
        return -1;
    }

    dip_cfg->shmt_id = id;
    dip_cfg->shmt_size = DISPENSER_SHMT_MALLOC_BUFFER;

    return 0;
}

void dispenser_shmt_del(struct dispenser_config *dip_cfg)
{
    if(&dip_cfg->rw_lock != NULL)
        pthread_mutex_destroy(&dip_cfg->rw_lock);

    shmctl(dip_cfg->shmt_id, IPC_RMID, 0);
}

static void *__dispenser_get_shmt_addr(struct dispenser_config *dip_cfg)
{
    void *addr = NULL;

    addr = shmat(dip_cfg->shmt_id, NULL, 0);
    if (!addr) {
        perror("shmat");
        return NULL;
    }
    return addr;
}

static int _dispenser_get_shmt_data(struct dispenser_config *dip_cfg, void *rsp)
{
    void *addr = NULL;
    int ret = -1;

    pthread_mutex_lock(&dip_cfg->rw_lock); 
    addr = __dispenser_get_shmt_addr(dip_cfg);
    if (NULL == addr) {
        perror("__dispenser_get_shmt_addr");
        goto OUT;
    }

    memcpy(rsp, addr, dip_cfg->shmt_size); 
    ret = 0;
OUT:
    pthread_mutex_unlock(&dip_cfg->rw_lock); 
    return ret;
}

static int _dispenser_set_shmt_data(struct dispenser_config *dip_cfg, void *dat)
{
    void *addr = NULL;
    int ret = -1;

    pthread_mutex_lock(&dip_cfg->rw_lock); 
    addr = __dispenser_get_shmt_addr(dip_cfg);
    if (NULL == addr) {
        perror("__dispenser_get_shmt_data");
        goto OUT;
    }

    memcpy(addr, dat, dip_cfg->shmt_size); 
    ret = 0;
OUT:
    pthread_mutex_unlock(&dip_cfg->rw_lock); 
    return ret;
}

int dispenser_set_data(struct dispenser_config *dip_cfg, void *_from_user)
{
    return _dispenser_set_shmt_data(dip_cfg, _from_user);
}

int dispenser_get_data(struct dispenser_config *dip_cfg, void *_to_user)
{
    return _dispenser_get_shmt_data(dip_cfg, _to_user);
}